package services.impl;

import java.util.List;
import java.util.Vector;

import javax.ejb.EJB;
import javax.ejb.Stateless;

import services.ExchangeFormatService;
import services.ItemVentaService;
import services.PedidoVentaService;
import services.RodamientoService;
import services.VentaService;
import JMS.JMSService;
import dao.VentaDAO;
import entities.ItemVenta;
import entities.PedidoVenta;
import entities.RodamientoStock;
import entities.Venta;
import entities.xml.VentaXML;
import finals.Finals;

@Stateless
public class VentaServiceBean implements VentaService {

	@EJB
	private VentaDAO ventaDAO;
	@EJB
	private RodamientoService rodamientoService;
	@EJB
	private PedidoVentaService pedidoVentaService;
	@EJB
	private ItemVentaService itemVentaService;
	@EJB
	private ExchangeFormatService exchangeFormatService;
	@EJB
	private JMSService jmsService;

	@Override
	public Venta generarRemito(PedidoVenta pedidoVenta) {
		Venta venta = new Venta();
		List<ItemVenta> itemsVenta = pedidoVenta.getItems();
		for (ItemVenta item : itemsVenta) {
			RodamientoStock rodamientoStock = (RodamientoStock) rodamientoService.findRodamientoStock(item.getRodamiento());
			if (rodamientoStock != null) {
				item.setRodamiento(rodamientoStock); // Si no le seteo el rodamiento este, cuando se quiera guardar el pedidoVenta, se crearia un rodamiento nuevo
				if (rodamientoStock.getStock() >= item.getCantidad()) {
					this.disminuirStock_AgregarAVenta_QuitarDePedidoVenta(item, rodamientoStock, venta, pedidoVenta);
				} else {
					this.agregarStockAVentaYFaltanteAPedidoVenta_SetearStockEnCero(rodamientoStock, item, venta, pedidoVenta);
				}
			} else {
				// TODO ver que hacer si el rodamiento no existe
			}
		}
		
		this.eliminarItemsConCantidad0(pedidoVenta);
		if (pedidoVentaService.existePedidoVenta(pedidoVenta)) {
			// no me fijo si tiene items porque puede ser que se le hayan eliminado
			pedidoVentaService.merge(pedidoVenta);
		} else {
			//Me fijo si tiene items porque sino voy a guardar un pedido de venta sin sentido
			if (pedidoVenta.getItems().size() > 0) {
				pedidoVentaService.persist(pedidoVenta);
			}
		}

		venta.setClienteId(pedidoVenta.getClienteId());
		// this.traerRodamientosDeDBaItemsVenta(venta.getItems());
		if (venta.getItems().size() > 0) {
			//Me fijo si tiene items porque sino voy a guardar una venta sin sentido
			this.persist(venta);
		}

		return venta;
	}

	private void eliminarItemsConCantidad0(PedidoVenta pedidoVenta) {
		List<ItemVenta> items = pedidoVenta.getItems();
		List<ItemVenta> itemsAEliminar = new Vector<ItemVenta>();
		for (ItemVenta itemVenta : items) {
			if(itemVenta.getCantidad()<=0){
				itemsAEliminar.add(itemVenta);
			}
		}
		for (ItemVenta itemVenta : itemsAEliminar) {
			items.remove(itemVenta);
			//Si es un pedidoVenta que vino de la BD, cuando le saco los items, tengo que eliminarlos porque sino quedan colgados en la base
			if(pedidoVenta.getId() != null){
				pedidoVentaService.merge(pedidoVenta);
				itemVentaService.delete(itemVenta.getId());
			}
		}
	}

	private void disminuirStock_AgregarAVenta_QuitarDePedidoVenta(ItemVenta item, RodamientoStock rodamientoStock, Venta venta,PedidoVenta pedidoVenta) {
		ItemVenta itemVenta = new ItemVenta(rodamientoStock, item.getCantidad(), item.getListaPreciosId(), item.getCotizacionId());
		//lo disminuyo al final porque sino se le seteaba el stock 0 al item venta
		rodamientoService.disminuirStock(item.getCantidad(), rodamientoStock);
		venta.getItems().add(itemVenta);
		//En vez d eliminar el item Lo que hace que se rompa el foreach) lo seteo en cero y despues de recorrer toda la lista elimino los itemos con 0 stock
		//pedidoVenta.getItems().remove(item);
		item.setCantidad(0);
	}

	private void agregarStockAVentaYFaltanteAPedidoVenta_SetearStockEnCero(RodamientoStock rodamientoStock, ItemVenta itemPedidoVentaViejo,Venta venta, PedidoVenta pedidoVenta) {
		Integer stockActual = rodamientoStock.getStock();
		Integer stockFaltante = rodamientoService.disminuirStock(itemPedidoVentaViejo.getCantidad(), rodamientoStock);
		ItemVenta itemVenta = new ItemVenta(rodamientoStock, stockActual, itemPedidoVentaViejo.getListaPreciosId(), itemPedidoVentaViejo.getCotizacionId());
		// Solo se genera la venta del item si su stock es mayor a 0
		if (itemVenta.getCantidad() > 0) {
			venta.getItems().add(itemVenta);
		}
		// a continuacion busco el item en el pedido venta y se seteo el stock
		// faltante, si se elimina el viejo y se pone uno nuevo se rompe el
		// foreach
		pedidoVenta.getItems().get(pedidoVenta.getItems().indexOf(itemPedidoVentaViejo)).setCantidad(stockFaltante);
		// pedidoVenta.getItems().add(itemPedidoVentaNuevo);
		// pedidoVenta.getItems().remove(itemPedidoVentaViejo);
	}

	// private void traerRodamientosDeDBaItemsVenta(List<ItemVenta> itemsVenta){
	// for(ItemVenta itemVenta : itemsVenta){
	// Rodamiento rodamientoSinId = itemVenta.getRodamiento();
	// Rodamiento rodamiento = rodamientoService.find(rodamientoSinId);
	// itemVenta.setRodamiento(rodamiento);
	// }
	// }

	@Override
	public Venta generarYEnviarRemito(PedidoVenta pedidoVenta) {
		Venta remito = this.generarRemito(pedidoVenta);
		if(!remito.getItems().isEmpty()){
			this.enviarRemitoAofV(remito, pedidoVenta.getOfVentaAlias());
		}
		return remito;
	}

	@Override
	public void enviarRemitoAofV(Venta remito, String ofVentaAlias) {
		String strRemitoXML = exchangeFormatService.toEF(remito, new VentaXML());
		jmsService.enviarJMS(strRemitoXML, Finals.COLAS.get(ofVentaAlias), Finals.IPS.get(ofVentaAlias));
	}

	@Override
	public int generarYEnviarRemitosAPartirDeStockNuevo() {
		int cantRemitosRealizados = 0;
		List<RodamientoStock> rodamientos = this.rodamientoService.findRodamientosConStockNuevo();
		List<PedidoVenta> pedidosVenta = pedidoVentaService.findAllOrderByFecha();
		for (PedidoVenta pedidoVenta : pedidosVenta) {
			Venta venta = new Venta();
			List<ItemVenta> itemsVenta = pedidoVenta.getItems();
			for (ItemVenta item : itemsVenta) {
				for (RodamientoStock rodamientoStock : rodamientos) {
					if (item.getRodamiento().equals(rodamientoStock)) {
						if (rodamientoStock.getStock() >= item.getCantidad()) {
							this.disminuirStock_AgregarAVenta_QuitarDePedidoVenta(item, rodamientoStock, venta, pedidoVenta);
						} else {
							this.agregarStockAVentaYFaltanteAPedidoVenta_SetearStockEnCero(rodamientoStock, item, venta, pedidoVenta);
						}
					}
				}
			}
			this.eliminarItemsConCantidad0(pedidoVenta);
			if (pedidoVenta.getItems().isEmpty()) {
				pedidoVentaService.delete(pedidoVenta.getId());
			} else {
				pedidoVentaService.merge(pedidoVenta);
			}
			if (venta.getItems().size() > 0){
				venta.setClienteId(pedidoVenta.getClienteId());
				this.persist(venta);
				this.enviarRemitoAofV(venta, pedidoVenta.getOfVentaAlias());
				cantRemitosRealizados ++;
			}
		}

		for (RodamientoStock rodamiento : rodamientos) {
			rodamiento.setHasStockNuevo(false);
			rodamientoService.merge(rodamiento);
		}
		return cantRemitosRealizados;
	}

	@Override
	public void delete(Object id) {
		ventaDAO.delete(id);
	}

	@Override
	public void persist(Venta entity) {
		ventaDAO.persist(entity);
	}

	@Override
	public Venta merge(Venta entity) {
		return ventaDAO.merge(entity);
	}

	@Override
	public List<Venta> findAll() {
		return ventaDAO.findAll();
	}

	@Override
	public Venta findByID(Object id) {
		return ventaDAO.findByID(id);
	}

}
